import hashlib
import os
import shutil
import urllib.parse
from datetime import datetime
from urllib.parse import unquote

import pymysql
from flask import Response, stream_with_context, Flask, request

app = Flask(__name__)
UPLOAD_FOLDER = 'upload/'


class MysqlClient:
    def __init__(self):
        self.host = "127.0.0.1"
        self.user = "root"
        self.password = "pie2983"
        self.database = "webdisk"
        self.conn = None
        self.cursor = None

    def connect(self):
        self.conn = pymysql.connect(host=self.host, user=self.user, password=self.password, database=self.database)
        self.cursor = self.conn.cursor()

    def close(self):
        if self.cursor:
            self.cursor.close()
        if self.conn:
            self.conn.close()

    def query(self, sql):
        self.connect()
        self.cursor.execute(sql)
        result = self.cursor.fetchall()
        self.close()
        return result

    def add_files(self, data):
        sql = f"INSERT INTO Files VALUES (NULL,'{data[0]}','{data[1]}','{data[2]}','{data[3]}','{data[4]}','{data[5]}','{data[6]}',{data[7]})"
        self.connect()
        self.cursor.execute(sql)
        self.conn.commit()
        self.close()

    def update(self, table, data, condition):
        set_str = ', '.join([f"{k} = %s" for k in data.keys()])
        sql = f"UPDATE {table} SET {set_str} WHERE {condition}"
        self.connect()
        self.cursor.execute(sql, tuple(data.values()))
        self.conn.commit()
        self.close()

    # 对记录的删除，在删除文件后调用
    def delete(self, path, user_key):
        condition = f"user_key = {user_key} AND CONCAT(path,name)='{path}'"
        sql = f"DELETE FROM Files WHERE {condition}"
        self.connect()
        self.cursor.execute(sql)
        self.conn.commit()
        self.close()
        return self.cursor.rowcount == 1

    # 对用户的删除，在注销后调用
    def delete_user(self, user_id):
        sql = f"DELETE FROM Users WHERE id={user_id}"
        self.connect()
        self.cursor.execute(sql)
        self.conn.commit()
        self.close()
        return self.cursor.rowcount == 1

    # 更新数据库的名称，在重命名后的调用
    def update_name(self, path, user_key, new_name):
        condition = f"user_key = {user_key} AND CONCAT(path, name) = '{path}'"
        sql = f"UPDATE Files SET name = '{new_name}' WHERE {condition}"
        self.connect()
        self.cursor.execute(sql)
        self.conn.commit()
        self.close()
        return self.cursor.rowcount == 1


client = MysqlClient()


# 返回用户id
def check_user(account, password):
    # 查询数据
    result = client.query(f"SELECT id from Users WHERE account='{account}' and `password`='{password}'")
    if result:
        return result[0][0]
    else:
        return False


# 返回用户是否管理员,不适合重写上面函数，因为最开始未设计，后期修改将是个大工程
# 管理员仅支持对其他人文件删除
def check_user_admin(account, password):
    # 查询数据
    result = client.query(f"SELECT `key` from Users WHERE account='{account}' and `password`='{password}'")
    if result:
        return result[0][0]
    else:
        return False


# 返回文件是否共享
def IsFilePublic(FilesID):
    # 查询数据
    result = client.query(f"Select public from Files where id={FilesID}")
    if result:
        return result[0][0]
    else:
        return False


# 根据文件ID返回文件路径
def down_load(filesID, userID=None):
    # 查询数据
    if userID == None:  # 下载共享文件
        print("下载共享")
        result = client.query(f"SELECT CONCAT(path,name),user_key,name FROM `Files` where id={filesID} AND public=1")
    else:  # 需要满足下载者为所有者才会被调用
        result = client.query(
            f"SELECT CONCAT(path,name),user_key,name FROM `Files` where id={filesID} AND user_key={userID}")
    if result:
        return result[0]
    else:
        return False


def md5_file(file_path):
    with open(file_path, 'rb') as f:
        md5 = hashlib.md5()
        while True:
            data = f.read(8192)
            if not data:
                break
            md5.update(data)
    return md5.hexdigest()


@app.route('/upload', methods=['POST'])
def upload_file():
    account = request.form.get('account')
    password = request.form.get('password')
    if account and password:
        id = check_user(account, password)
        # 判断有无文件
        if 'file' not in request.files:
            return 'No file part'
        file = request.files['file']
        # 文件名称为空
        if file.filename == '':
            return 'No selected file'
        # 文件类型判别
        type = request.form.get('type')
        filename = unquote(file.filename)
        if type == "audio":
            path = UPLOAD_FOLDER + f"{str(id)}/audio/"
            file.save(os.path.join(path, filename))
        elif type == "photo":
            path = UPLOAD_FOLDER + f"{str(id)}/album/"
            file.save(os.path.join(path, filename))
        else:
            path = UPLOAD_FOLDER + f"{str(id)}/files/"
            file.save(os.path.join(path, filename))
        # 账户判别，共享账户的所有文件均为共享
        public = 0  # 默认为不共享
        if id == 1:
            public = 1
        # 添加文件数据
        # 与数据库对应，name path size date user_key md5 type
        data = [filename, path.replace(UPLOAD_FOLDER + str(id), ""),
                round(os.path.getsize(f"{path + filename}") / (1024 * 1024), 2), datetime.now(), id,
                md5_file(f"{path + filename}"), type, public]
        # 实例化数据库
        sql = MysqlClient()
        # 插入文件记录
        sql.add_files(data)
        return 'File uploaded successfully'
    else:
        return "无账户密码"


@app.route('/manage/delete/all', methods=['POST'])
def delete_folder():
    print("删除文件夹")
    account = request.form.get('account')
    password = request.form.get('password')
    if account and password:
        id = check_user(account, password)
        if id:
            if os.path.exists(UPLOAD_FOLDER + str(id)):
                # 删除用户文件夹，注销用户
                shutil.rmtree(UPLOAD_FOLDER + str(id))
                # 实例化数据库
                sql = MysqlClient()
                sql.delete_user(id)
                return "用户已注销"
            else:
                return "账户未找到"
        else:
            return "账户密码异常"
    else:
        return "参数错误"


@app.route('/download', methods=['GET'])
def download_file():
    account = request.args.get('account')
    password = request.args.get('token')
    filesID = request.args.get('filesID')
    # 存在账户与密码
    if account and password:
        id = check_user(account, password)
        # 判断用户id，共享账户与共享文件获取文件路径
        if id == 1 or IsFilePublic(filesID) == 1:
            path_list = down_load(filesID)
            # 文件路径拼接
            path = str(path_list[1]) + path_list[0]
            print(UPLOAD_FOLDER + str(id) + str(path))
        else:
            # 普通用户使用文件ID与用户ID获取文件
            path_list = down_load(filesID, id)
            path = str(path_list[1]) + path_list[0]
            print(UPLOAD_FOLDER + str(id) + str(path))
        # 文件路径拼接后反弹文件绝对路径
        if path:
            # 下载路径
            file_path = "/data/data/com.termux/files/home/upload/" + path
            print("下载路径", file_path)
            # 获取文件大小
            file_size = os.path.getsize(file_path)

            # 文件切片
            def generate():
                with open(file_path, "rb") as f:
                    while True:
                        chunk = f.read(1024)
                        if not chunk:
                            break
                        yield chunk

            # 回弹二进制切片文件
            response = Response(stream_with_context(generate()), mimetype='application/octet-stream')
            # 文件大小
            response.headers['Content-Length'] = str(file_size)  # Add the size of the file in the header
            # 文件名称
            response.headers['Content-Disposition'] = 'attachment; filename={}'.format(
                urllib.parse.quote(os.path.basename(path_list[2]), safe=''))
            print(file_path, file_size)
            # 返回下载资源
            return response
        else:
            return "无文件或无权限"
    else:
        return "账户密码异常"
    return "参数错误"


@app.route('/bulid', methods=['POST'])
def handle_post():
    account = request.form.get('account')
    password = request.form.get('password')
    # print(account)
    if account and password:
        id = check_user(account, password)
        if id:
            if os.path.exists(UPLOAD_FOLDER + "/" + str(id)):
                return "已构建"
            else:
                os.makedirs(UPLOAD_FOLDER + "/" + str(id))
                os.makedirs(f"{UPLOAD_FOLDER}/{str(id)}/files")
                os.makedirs(f"{UPLOAD_FOLDER}/{str(id)}/album")
                os.makedirs(f"{UPLOAD_FOLDER}/{str(id)}/audio")
                os.makedirs(f"{UPLOAD_FOLDER}/{str(id)}/backup")
        else:
            return "账户密码异常"
    return "构建完成"

    # id = check_user('29837176131', "3ea87a56da3844b420ec2925ae922bc731ec16a4fc44dcbeafdad49b0e61d39c")
    # ... 获取其他字段的值


@app.route('/manage/delete', methods=['POST'])
def delete_file():
    file_path = ""
    print("删除文件")
    account = request.form.get('account')
    password = request.form.get('password')
    filesID = request.form.get('filesID')
    file_path = unquote(request.form.get('file_path'))
    print(file_path)
    if account and password:
        id = check_user(account, password)
        if id:
            key = check_user_admin(account, password)
            if key == 'admin':  # 管理员时，id为查询后的id
                id = down_load(filesID)[1]
            if os.path.exists(UPLOAD_FOLDER + str(id)):
                if os.path.exists(UPLOAD_FOLDER + str(id) + file_path):
                    os.remove(UPLOAD_FOLDER + str(id) + file_path)
                    # 实例化数据库
                    sql = MysqlClient()
                    # 删除文件记录，返回1表示已删除1行
                    if (sql.delete(file_path, id) == 1):
                        return "删除成功"
                    return "文件已删除"
                else:
                    return "文件路径不存在" + UPLOAD_FOLDER + str(id) + file_path
            else:
                return "账户未找到"
        else:
            return "账户密码异常"
    else:
        return "参数错误"


@app.route('/manage/rename', methods=['POST'])
def rename_file():
    file_path = ""
    new_file_name = ""
    print("重命名文件")
    account = request.form.get('account')
    password = request.form.get('password')
    file_path = unquote(request.form.get('file_path'))
    new_file_name = unquote(request.form.get('new_name'))
    if account and password:
        id = check_user(account, password)
        if id:
            if os.path.exists(UPLOAD_FOLDER + str(id)):
                if os.path.exists(UPLOAD_FOLDER + str(id) + file_path):
                    # 旧文件名称
                    old_file_path = os.path.join(UPLOAD_FOLDER, str(id) + file_path)
                    # 新文件名称
                    new_file_path = os.path.join(UPLOAD_FOLDER,
                                                 str(id) + file_path[:file_path.rfind('/') + 1] + new_file_name)
                    print(old_file_path, new_file_path)
                    os.rename(old_file_path, new_file_path)
                    # 实例化数据库
                    sql = MysqlClient()
                    # 插入文件记录
                    if (sql.update_name(file_path, id, new_file_name)):
                        return "文件已重命名"
                    return "重命名"
                else:
                    return "文件路径不存在" + UPLOAD_FOLDER + str(id) + file_path
            else:
                return "账户未找到"
        else:
            return "账户密码异常"
    else:
        return "参数错误"


@app.route('/manage/ai', methods=['POST'])
def ai_file():
    print("文件解释")
    account = request.form.get('account')
    password = request.form.get('password')
    filesID = request.form.get('filesID')
    if account and password:
        id = check_user(account, password)
        public = IsFilePublic(filesID)
        print(f"AI解释：{account} {password} {filesID} {id}")
        # 非共享账户权限
        # 共享文件，ID为他人
        if public == 1:
            path_list = down_load(filesID)
            path = str(path_list[1]) + path_list[0]
            print(UPLOAD_FOLDER + str(id) + str(path))
        elif public == 0:
            path_list = down_load(filesID, id)
            path = str(path_list[1]) + path_list[0]
            print(UPLOAD_FOLDER + str(id) + str(path_list))
        else:
            path = None
        print(path)
        if path != None and path != "":
            file_path = "/data/data/com.termux/files/home/upload/" + path
            with open(file_path, 'r', encoding='utf-8') as file:
                content = file.read()
            return str(content)
        else:
            return "无文件或无权限"
    else:
        return "账户密码异常"


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=6767, debug=True)
